function on(dom, event_name, handler_selector, delegation_handler) {
  if (
    typeof handler_selector === "string" &&
    typeof delegation_handler === "function"
  ) {
    return delegation(dom, event_name, handler_selector, delegation_handler);
  }
  // 在dom对象里面建立一个事件名 : 事件处理函数对应的数组;
  // 判定当前事件处理函数是否在dom对象之中;
  var event_type = "_" + event_name;
  if (event_type in dom) {
    dom[event_type].push(handler_selector);
  } else {
    dom[event_type] = [handler_selector];
  }
  // 如果直接用事件名当成对象之中的key值，那么会和原有的dom功能名称冲突;
  // 因为特殊的事件名会导致事件无法触发，所以我们在这里要对事件名进行拆分处理;
  dom.addEventListener(event_name.split(".")[0], handler_selector);
}
function off(dom, event_name) {
  // 获取到dom对象里面事件名对应的一组事件处理函数;
  var callback_list = dom["_" + event_name];
  // 根据列表里面的所有函数进行事件移除 ;
  callback_list.forEach(function (event_handler) {
    dom.removeEventListener(event_name.split(".")[0], event_handler);
  });
  // 清空dom对象里面的事件处理函数组;
  dom["_" + event_name].length = 0;
}

function trigger(dom, event_type) {
  dom.dispatchEvent(new Event(event_type));
}

function delegation(dom, event_name, selector, event_handler) {
  dom.addEventListener(event_name, function (e) {
    e = e || event;
    var target = e.target || e.srcElement;

    try {
      while (target !== dom) {
        e.origin = target;
        switch (selector[0]) {
          case ".":
            if (selector.slice(1) === target.className) {
              event_handler.call(target, e);
              return;
            }
          case "#":
            if (selector.slice(1) === target.id) {
              event_handler.call(target, e);
              return;
            }
          default:
            if (selector.toUpperCase() === target.nodeName) {
              event_handler.call(target, e);
              return;
            }
        }
        target = target.parentNode;
      }
    } catch (e) {}
  });
}

function animate(dom, attrs, callback, transition = "buffer", speed = 10) {
  // transition : 有两种动画方式 "buffer" , "liner"
  var _style = getComputedStyle(dom);

  // - 1. 数据变形 ;
  for (var attr in attrs) {
    attrs[attr] = {
      target: attrs[attr],
      now: _style[attr],
    };
    // - 2. 速度 : 匀速运动速度正负 ;
    if (transition === "liner") {
      attrs[attr].speed = attrs[attr].target > attrs[attr].now ? speed : -speed;
    }

    if (attr === "opacity") {
      attrs[attr].target *= 100;
      attrs[attr].now *= 100;
    } else {
      attrs[attr].now = parseInt(attrs[attr].now);
    }
  }
  // - 关闭开启定时器;
  clearInterval(dom.interval);
  dom.interval = setInterval(function () {
    for (var attr in attrs) {
      // 取出当前值和属性值 ;
      // attrs[attr].target : 目标值;
      // attrs[attr].now    : 当前值;

      let { target, now } = attrs[attr];

      // 缓冲运动时候的速度;
      if (transition === "buffer") {
        var speed = (target - now) / 10;
        speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
      } else if (transition === "liner") {
        var speed = attrs[attr].speed;
      }

      if (Math.abs(target - now) <= Math.abs(speed)) {
        if (attr === "opacity") {
          dom.style[attr] = target / 100;
        } else {
          dom.style[attr] = target + "px";
        }

        delete attrs[attr];
        for (var attr in attrs) {
          // 如果有数据循环会执行至少一次;
          return false;
        }
        clearInterval(dom.interval);
        typeof callback === "function" ? callback() : "";
      } else {
        now += speed;

        if (attr === "opacity") {
          dom.style[attr] = now / 100;
        } else {
          dom.style[attr] = now + "px";
        }
        // 给对象赋值;
        attrs[attr].now = now;
      }
    }
  }, 30);
}
var throttling = (function () {
  var t = null;
  return function (callback, delay = 200) {
    // 如果t不是null那么我们就不允许代码执行;
    if (t !== null) {
      return;
    }
    t = setTimeout(function () {
      // 放入你想要执行的代码;
      callback();
      // 重置t;
      t = null;
    }, delay);
  };
})();



class lazyLoad {
      // constructor
      constructor(selector) {
          this.imgs = Array.from(document.querySelectorAll(selector))
          this.top_offset = this.imgs.map((item) => this.getAbsoluteTop(item))
          this.bindEvent()
          window.dispatchEvent(new Event("scroll"))
      }
  
      // All events in here
      bindEvent() {
          window.onscroll=() => {
              for (let i = 0; i < this.top_offset.length; i++) {
                if (this.top_offset[i] <= scrollY + innerHeight) {
                  let img = new Image()
                  img.src = this.imgs[i].getAttribute("data-src")   
                  img.onload = () => {
                    this.imgs[i].src = this.imgs[i].getAttribute("data-src")
  
                      }
                  }
              }
          }
      }
      // getAbsoluteTop
      getAbsoluteTop(dom) {
          if (dom.offsetParent !== document.body) {
              return dom.offsetTop + this.getAbsoluteTop(dom.offsetParent)
          }
          return dom.offsetTop
      }
  }



function jsonp(options) {
  options = Object.assign(
    {
      jsonp: "callback",
    },
    options
  );

  // 定义全局函数名;
  // 定义一个绝对惟一的全局函数名;
  let random_name = ("gp" + Math.random() + "_" + Date.now()).replace(
    /(?<=gp)0\.0*/,
    ""
  );

  var script = document.createElement("script");
  // url?key=value&key2=value2

  var _data = formatData(options.data);
  _data += "&" + options.jsonp + "=" + random_name;

  options.url = options.url + (/\?/.test(options.url) ? "&" : "?") + _data;
  script.src = options.url;

  document.body.appendChild(script);

  script.remove();

  return new Promise(function (fulfill, reject) {
    window[random_name] = function (res) {
      fulfill(res);
      typeof options.success === "function" ? options.success(res) : "";
      delete window[random_name];
    };
  });
}

function ajax(options) {
  if (options.dataType === "jsonp") {
    return jsonp(options);
  }

  var xhr = new XMLHttpRequest();
  // 处理data数据;
  // 遍历data数据把data数据变成一个字符串;
  // "key=value&key2=value"

  options = Object.assign(
    {
      type: "GET",
    },
    options
  );

  var data = formatData(options.data);

  // 什么时候我们想url拼接请求数据 ;
  // 为GET的请情况下把数据拼接到url上面 ;
  if (options.type.toUpperCase() === "GET") {
    options.url += (/\?/.test(options.url) ? "&" : "?") + data;
  }

  if (options.credentials) {
    xhr.withCredentials = true;
  }

  xhr.open(options.type, options.url, true);
  if (options.type.toUpperCase() === "POST") {
    xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
  }

  // 判定 this.headers 是对象;
  if (
    typeof options.headers === "object" &&
    options.headers !== null &&
    !(options.headers instanceof Array)
  ) {
    for (var attr in options.headers) {
      xhr.setRequestHeader(attr, options.headers[attr]);
    }
  }
  // 如果是post请求，数据用send放在请求体之中;
  xhr.send(options.type.toUpperCase() === "POST" ? data : null);

  return new Promise(function (fulfill, reject) {
    xhr.onreadystatechange = function () {
      // 根据xhr状态码和http状态码，对回调函数进行调用处理;
      // - 成功 ;
      // - 失败 ;
      if (xhr.readyState === 4 && /^2\d{2}$/.test(xhr.status)) {
        // 获取响应结果;
        var res = xhr.responseText;
        // 判定结果处理类型;
        switch (options.dataType) {
          case "json":
            // 把json字符串转换成对象类型
            res = JSON.parse(res);
            break;
          case "text":
            res = res.replace(/([<>])/g, function ($1) {
              // 这个函数的返回值去替换我们查询到的字符;
              switch ($1) {
                case "<":
                  return "&lt;";
                case ">":
                  return "&gt;";
              }
            });
            break;
          case "html":
            break;
        }
        fulfill(res);
        typeof options.success === "function" ? options.success(res) : "";
      } else if (xhr.readyState === 4) {
        typeof options.error === "function" ? options.error() : "";
        reject(xhr.status);
      }
    };
  });
}

function formatData(data) {
  var _data = "";
  for (var key in data) {
    _data += "&" + key + "=" + data[key];
  }
  _data = _data.slice(1);

  return _data;
}

function cookie(name, value, options = {}) {
  // setCookie
  if (
    typeof name === "string" &&
    (typeof value === "string" || typeof value === "number")
  ) {
    // 因为日期对象比较特殊所以我们需要先创建日期对象;
    // 传入的数据要求是number 类型, 代表的涵义是cookie在几天之后过期;
    if (typeof options.expires === "number") {
      var d = new Date();
      d.setDate(d.getDate() + options.expires);
      options.expires = d;
    }
    // 把所有的参数拼接成符合cookie规则的字符串;
    return (document.cookie = [
      name,
      "=",
      value,
      typeof options.path === "string" ? ";path=" + options.path : "",
      typeof options.domain === "string" ? ";domain=" + options.domain : "",
      typeof options.expires === "object" ? ";expires=" + options.expires : "",
    ].join(""));
  }
  // removeCookie
  if (typeof name === "string" && value === null) {
    return cookie(
      name,
      "delete",
      Object.assign(
        {
          expires: -1,
        },
        options
      )
    );
  }
  // getCookie
  if (typeof name === "string") {
    // 拆分的依据一定是 : 分号*空格*; 一定要记住是有空格的;
    var cookie_array = document.cookie.split("; ");
    // 遍历cookie数组查询正确的cookie数据;
    for (var i = 0; i < cookie_array.length; i++) {
      var item = cookie_array[i].split("=");
      if (item[0] === name) {
        return item[1];
      }
    }
    return "";
  }
}
